// Kony

//继承自部件控制器基类的，覆盖层小部件控制器，目前主要用于主界面UI
#include "UI/WidgetController/OverlayWidgetController.h"

#include "BaseGameplayTags.h"
#include "AbilitySystem/BaseAbilitySystemComponent.h"
#include "AbilitySystem/BaseAttributeSet.h"
#include "AbilitySystem/Data/AbilityInfo.h"
#include "AbilitySystem/Data/LevelConfig.h"
#include "Player/BasePlayerState.h"

//广播初始化值 用于广播用户属性数据
void UOverlayWidgetController::BroadcastInitializeValues()
{
	//这是子类 父类在BaseWidgetController.h中定义的广播初始化值函数
	//获取用户属性集 读取属性
	// const UBaseAttributeSet* BaseAttributeSet = GetBaseAS();
	/** 新增属性 需要修改这里 增加添加广播到界面 **/
	//广播生命值
	OnHealthChanged.Broadcast(GetBaseAS()->GetHealth());
	//广播最大生命值
	OnMaxHealthChanged.Broadcast(GetBaseAS()->GetMaxHealth());
	//广播魔法值
	OnManaChanged.Broadcast(GetBaseAS()->GetMana());
	//广播最大魔法值
	OnMaxManaChanged.Broadcast(GetBaseAS()->GetMaxMana());
	//广播幽灵生命值
	OnGhostHealthChanged.Broadcast(GetBaseAS()->GetGhostHealth());
	//广播幽灵魔法值
	OnGhostManaChanged.Broadcast(GetBaseAS()->GetGhostMana());
}

void UOverlayWidgetController::BindCallbacksToDependencies()
{
	//这是子类 父类在BaseWidgetController.h中定义的绑定回调函数
	//每当数值变化时该函数被调用
	//获取用户状态 读取等级相关数据
	// ABasePlayerState* BasePlayerState = CastChecked<ABasePlayerState>(PlayerState);
	GetBasePS()->OnXPChangedDelegate.AddUObject(this, &UOverlayWidgetController::OnXPChanged);
	GetBasePS()->OnLingQiChangedDelegate.AddUObject(this, &UOverlayWidgetController::OnLingQiChanged);
	//广播玩家等级变动
	GetBasePS()->OnLevelChangedDelegate.AddLambda([this](int32 NewLevel,bool bLevelUp)
	{
		OnPlayerLevelChangedDelegate.Broadcast(NewLevel, bLevelUp);
	});
	//获取用户属性集 读取属性
	// const UBaseAttributeSet* BaseAttributeSet = GetBaseAS();
	//绑定回调函数
	/** 新增属性 需要修改这里 增加注册到GAS的变化触发广播回调 **/
	//注册GAS生命值发生变化时回调
    //  AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetHealthAttribute())
	// .AddUObject(this, &UOverlayWidgetController::HealthChanged); 旧版写法
	//新版直接使用 Lambda表达式来接收委托数据直接调用广播到HUD界面
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetHealthAttribute())
   .AddLambda([this](const FOnAttributeChangeData& Data){OnHealthChanged.Broadcast(Data.NewValue);});
	//注册GAS最大生命值发生变化时回调
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetMaxHealthAttribute())
   .AddLambda([this](const FOnAttributeChangeData& Data){OnMaxHealthChanged.Broadcast(Data.NewValue);});
	//注册GAS法力值发生变化时回调
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetManaAttribute())
   .AddLambda([this](const FOnAttributeChangeData& Data){OnManaChanged.Broadcast(Data.NewValue);});
	//注册GAS最大法力值发生变化时回调
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetMaxManaAttribute())
	.AddLambda([this](const FOnAttributeChangeData& Data){OnMaxManaChanged.Broadcast(Data.NewValue);});
	//注册GAS幽灵生命值发生变化时回调
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetGhostHealthAttribute())
	.AddLambda([this](const FOnAttributeChangeData& Data){OnGhostHealthChanged.Broadcast(Data.NewValue);});
	//注册GAS幽灵法力值发生变化时回调
	AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(GetBaseAS()->GetGhostManaAttribute())
	.AddLambda([this](const FOnAttributeChangeData& Data){OnGhostManaChanged.Broadcast(Data.NewValue);});

	if (GetBaseASC())
	{
		//绑定法术装备更变广播，用于技能栏拖拽技能
		GetBaseASC()->AbilityEquippedDelegate.AddUObject(this, &UOverlayWidgetController::OnAbilityEquipped);
		if (GetBaseASC()->bStartupAbilitiesGiven)
		{
			//如果已经绑定广播 则执行函数
			//改为调用基类组件的广播能力信息
			//如果需要添加能力信息 需要进入下面的函数增加对应的Info存储
			BroadcastAbilityInfo();
		}
		else
		{
			//绑定初始化启动能力技能委托，一旦赋予能力就会调用 BroadcastAbilityInfo 这个函数
			GetBaseASC()->AbilitiesGivenDelegate.AddUObject(this, &UOverlayWidgetController::BroadcastAbilityInfo);
		}
		//用于响应能力系统组件 游戏标签委托的 广播，AddLambda需要一个Lambda表达式 结构是 [](){}
		GetBaseASC()->EffectAssetTags.AddLambda(
			[this](const FGameplayTagContainer& AssetTags)
			{
				//循环广播接收到的标签容器
				for (const FGameplayTag Tag : AssetTags)
				{
					//举例 Tag = Message.HealthPotion
					//* "Message.HealthPotion".MatchesTag("Message") will return True, "Message".MatchesTag("Message.HealthPotion") will return False
					//这段的作用是判断这条TAG消息是否是Message标签下的子集，如果不是则跳过
					FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message"));
					if (Tag.MatchesTag(MessageTag))
					{
						//从数据表获取对应标签的数据
						const FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable, Tag);
						MessageWidgetRowDelegate.Broadcast(*Row);
					};
					//获取标签名称
					// FName TagName = Tag.GetTagName();
					// const FString Msg = FString::Printf(TEXT("GE Tag: %s"), *TagName.ToString());
					// 在屏幕上显示蓝色调试信息，持续8秒
					// GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Blue, Msg);
				}
			}
		);
	}
}

void UOverlayWidgetController::OnXPChanged(int32 NewXP)
{
	// ABasePlayerState* BasePlayerState = CastChecked<ABasePlayerState>(PlayerState);
	UDataTable* LevelConfigDataTable = GetBasePS()->LevelConfigDataTable;
	checkf(LevelConfigDataTable, TEXT("LevelConfigDataTable is null 请填写等级配置DataTable到玩家状态蓝图 BP_BasePlayerState"));
	
	//获取当前等级
	const int32 CurrentLevel = GetBasePS()->GetPlayerLevel();
	
	//获取当前等级升级所需经验值，优先使用缓存
	int32 XPRequiredForThisLevel = GetBasePS()->GetXPRequiredForNextLevel();
	if (XPRequiredForThisLevel == 0)
	{
		//如果缓存为0，则从数据表获取
		XPRequiredForThisLevel = ULevelConfig::GetXPRequiredForCurrentLevel(LevelConfigDataTable, CurrentLevel);
	}
	
	if (XPRequiredForThisLevel > 0)
	{
		//计算百分比：当前经验值 / 升级所需经验值
		const float XPBarPercent = static_cast<float>(NewXP) / static_cast<float>(XPRequiredForThisLevel);
		//广播到覆盖层界面
		OnXPPercentChangedDelegate.Broadcast(FMath::Clamp(XPBarPercent, 0.0f, 1.0f));
	}
}

void UOverlayWidgetController::OnLingQiChanged(int32 NewLingQi)
{
	//灵气值变化处理逻辑
	// ABasePlayerState* BasePlayerState = CastChecked<ABasePlayerState>(PlayerState);
	UDataTable* LevelConfigDataTable = GetBasePS()->LevelConfigDataTable;
	checkf(LevelConfigDataTable, TEXT("LevelConfigDataTable is null 请填写等级配置DataTable到玩家状态蓝图 BP_BasePlayerState"));
	
	//获取当前等级
	const int32 CurrentLevel = GetBasePS()->GetPlayerLevel();
	
	//计算灵气值百分比
	float LingQiPercent = ULevelConfig::CalculateLingQiPercent(LevelConfigDataTable, CurrentLevel, NewLingQi);
	
	//广播灵气值百分比到覆盖层界面
	OnLingQiPercentChangedDelegate.Broadcast(LingQiPercent);
}
//绑定技能栏装备技能函数,用于拖拽或法术菜单指定法术更变时，主覆盖页面的主技能栏跟随改变
void UOverlayWidgetController::OnAbilityEquipped(const FGameplayTag& AbilityTag, const FGameplayTag& Status, const FGameplayTag& Slot, const FGameplayTag& PreviousSlot) const
{
	const FBaseGameplayTags GameplayTags = FBaseGameplayTags::Get();
	//创建上一个槽位技能数据体
	FBaseAbilityInfo LastSlotInfo;
	//设置能力状态已解锁
	LastSlotInfo.StatusTag = GameplayTags.Abilities_Status_Unlocked;
	LastSlotInfo.InputTag = PreviousSlot;
	LastSlotInfo.AbilityTag = GameplayTags.Abilities_None;
	//如果前一个槽位是有效槽位 ,则广播清除上一个槽位 用于清除这个标签内上一个技能的标签
	AbilityInfoDelegate.Broadcast(LastSlotInfo);
	
	//创建当前新槽位技能数据体
	FBaseAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AbilityTag);
	Info.StatusTag = Status;
	Info.InputTag = Slot;
	//广播新装备技能信息
	AbilityInfoDelegate.Broadcast(Info);
}


/** 新增属性 需要修改这里 增加回调函数 这里是旧版写法 已经不需要了 **/
//生命值变化回调函数
// void UOverlayWidgetController::HealthChanged(const FOnAttributeChangeData& Data) const
// {
// 	OnHealthChanged.Broadcast(Data.NewValue);
// }
// //最大生命值变化回调函数
// void UOverlayWidgetController::MaxHealthChanged(const FOnAttributeChangeData& Data) const
// {
// 	OnMaxHealthChanged.Broadcast(Data.NewValue);
// }
// //魔法值变化回调函数
// void UOverlayWidgetController::ManaChanged(const FOnAttributeChangeData& Data) const
// {
// 	OnManaChanged.Broadcast(Data.NewValue);
// }
// //最大魔法值变化回调函数
// void UOverlayWidgetController::MaxManaChanged(const FOnAttributeChangeData& Data) const
// {
// 	OnMaxManaChanged.Broadcast(Data.NewValue);
// }
